package com.wisezone.workflow.core.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import com.wisezone.workflow.bean.WfActivity;
import com.wisezone.workflow.bean.WfActivityInstance;
import com.wisezone.workflow.bean.WfLink;
import com.wisezone.workflow.bean.WfVariable;
import com.wisezone.workflow.bean.WfVariableInstance;
import com.wisezone.workflow.bean.form.WfVariableForm;
import com.wisezone.workflow.bean.form.WfVariableInstanceForm;
import com.wisezone.workflow.bean.search.WfActivityInstanceSearch;
import com.wisezone.workflow.bean.search.WfLinkSearch;
import com.wisezone.workflow.bean.search.WfVariableInstanceSearch;
import com.wisezone.workflow.bean.search.WfVariableSearch;
import com.wisezone.workflow.core.Activity;
import com.wisezone.workflow.core.ActivityInstance;
import com.wisezone.workflow.core.BaseProperty;
import com.wisezone.workflow.core.FlowEngine;
import com.wisezone.workflow.core.Link;
import com.wisezone.workflow.core.ProcessDefinition;
import com.wisezone.workflow.core.ProcessInstance;
import com.wisezone.workflow.exception.WfCoreException;
import com.wisezone.workflow.exec.ActivityExecHelper;



/**
 * 活动实例对象
 * 
 * @author tss 2009-09-05
 * 
 */
public class ActivityInstanceImpl extends BasePropertyImpl implements
		ActivityInstance {

	private WfActivityInstance wfActivityInstance;

	private ProcessDefinition processDefinition;

	private ProcessInstance processInstance;

	private Map<String, Object> variableMap = new HashMap<String, Object>();

	private Activity activity;

	private ActivityInstance currentActivityInst;
	
	private ActivityInstance previousActivityInst;  //上一个活动
	
	private ActivityInstance superActivityInst; // 父活动

	private Set<ActivityInstance> subActivityInst; // 子活动集合

	/**
	 * 构造方法
	 * 
	 * @param processInstance
	 * @param wfActivityInstance
	 * @param activity
	 */
	public ActivityInstanceImpl(ProcessInstance processInstance,
			WfActivityInstance wfActivityInstance, Activity activity) {

		this.processInstance = processInstance;
		this.processDefinition = processInstance.getProcessDefinition();
		this.activity = activity;
		this.wfActivityInstance = wfActivityInstance;
		previousActivityInst = null;
		currentActivityInst = this;
		superActivityInst = null;
		subActivityInst = null;
		this.setDao(processInstance);
	}

	/**
	 * 活动开始
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance start() throws WfCoreException {

		try {
			
			// 启动当前活动，并结束上一活动（如果有的话）
			WfActivityInstance wfActivityInst = currentActivityInst.getModel();
			wfActivityInst.setStartTime(new Date());
			
			//一开始状态
			currentActivityInst.getModel().setState(
					getActivityInstState(ACTIVITY_INST_START)); 
			
			//活动完成开始后代码编写
			if (currentActivityInst.getActivity().getModel().getCategory()
					.equals(getActivityCategory(ACTIVITY_TIMER))) { // 定时器
				ActivityExecHelper.timerRun(currentActivityInst, this.getWfVariableInstanceDao(),
						this.getWfVariableDao());
			}

			return this;

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}
	
	/**
	 * 活动开始
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance start(Map<String, Object> _variableMap) throws WfCoreException {
		
		try {
			
			//设置变量
			setActivityVariables(_variableMap);
			
			start();
			return this;
			
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 活动实例完成
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance complete(Long actor, String opinion)
	throws WfCoreException {
		
		if(actor == null){
			throw new IllegalArgumentException("活动参与人ID不能为空");
		}
		try {
			start();
			setActor(actor);
			setOpinion(opinion);
			return end();
			
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}
	
	/**
	 * 活动实例完成
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance complete(Long actor, Long[] nextActorIds,
			Long[] nextActorGroupIds,String opinion) throws WfCoreException {
		if(actor == null){
			throw new IllegalArgumentException("活动参与人ID不能为空");
		}
		try {
			start();
			setActor(actor);
			setOpinion(opinion);
			return end(nextActorIds, nextActorGroupIds);

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}
	
	

	/**
	 * 活动实例完成
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance complete(Long actor,
			Map<String, Object> activityMap,Map<String,Object> variableMap,String opinion)
			throws WfCoreException {
		
		if(actor == null){
			throw new IllegalArgumentException("活动参与人ID不能为空");
		}
		try {
			start();
			setActor(actor);
			setOpinion(opinion);
			setActivityVariables(variableMap);
			return end(activityMap);

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}
	

	/**
	 * 活动结束
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance end() throws WfCoreException {
		try {

			Long nextActivityId = this.getProcessDefinition().loadEndActivity().getModel().getId();
			return endActivity(nextActivityId, null, null);

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 活动结束
	 * map 封装参数
	 * NEXT_LINK_ID ： 下一链接ID
	 * NEXT_ACTIVITY_ID：下一活动ID
	 * ACTOR_IDS：下一活动参与者集合
	 * ACTOR_GROUP_IDS：下一活动参与用户组集合
	 * @param map 
	 * 
	 * @return 
	 * @throws WfCoreException
	 */
	public ActivityInstance end(Map<String, Object> map) throws WfCoreException {

		Long nextActivityId = null;
		if(map == null){
			return end();
		}
		if(map.containsKey(NEXT_LINK_ID)){
			Long linkId = Long.valueOf(map.get(NEXT_LINK_ID).toString());
			WfLink wfLink = this.getWfLinkDao().load(linkId);
			nextActivityId = wfLink.getActivityId();
		}else if(map.containsKey(NEXT_ACTIVITY_ID)){
			nextActivityId = Long.valueOf(map.get(BaseProperty.NEXT_ACTIVITY_ID).toString());
		}else{
			return end();
		}
		Long[] nextActorIds = null;
		Long[] nextActorGroupIds = null;
		if (map.get(BaseProperty.ACTOR_IDS) != null) {
			nextActorIds = (Long[]) map.get(BaseProperty.ACTOR_IDS);
		}
		if (map.get(BaseProperty.ACTOR_GROUP_IDS) != null) {
			nextActorGroupIds = (Long[]) map.get(BaseProperty.ACTOR_GROUP_IDS);
		}
		
		return end(nextActivityId, nextActorIds, nextActorGroupIds);
	}

	/**
	 * 活动结束(自动流转第一个节点)
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance end(Long[] nextActorIds, Long[] nextActorGroupIds)
			throws WfCoreException {
		try {

			String transName = currentActivityInst.getActivity().getLinks().get(
					0).getModel().getName();
			Long preActivityId = currentActivityInst.getActivity().getModel().getId();
			Long nextActivityId = getNextActivitytId(preActivityId, transName);
			return endActivity(nextActivityId, nextActorIds, nextActorGroupIds);

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 活动结束于给定活动名
	 * 
	 * @param activityName
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance end(Long nextActivityId, Long[] nextActorIds,
			Long[] nextActorGroupIds) throws WfCoreException {

		return endActivity(nextActivityId, nextActorIds, nextActorGroupIds);
	}

	/**
	 * 设置活动参与者
	 * 
	 * @param starter
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance setActor(Long actor) throws WfCoreException {

		wfActivityInstance.setActor(actor);
		return this;
	}

	/**
	 * 设置活动意见
	 * 
	 * @param opinion
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance setOpinion(String opinion) throws WfCoreException {

		wfActivityInstance.setOpinion(opinion);
		return this;
	}

	/**
	 * 设置活动备注
	 * 
	 * @param memo
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance setMemo(String memo) throws WfCoreException {

		wfActivityInstance.setMemo(memo);
		return this;
	}

	/**
	 * 是否结束活动
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public boolean isEnd() throws WfCoreException {

		if (activity.getModel().getCategory().equals(
				getActivityCategory(ACTIVITY_END))) { // 结束节点
			return true;
		} else {
			return false;
		}

	}

	

	/**
	 * 修改
	 * 
	 * @param wfActivityInstance
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance update(WfActivityInstance wfActivityInstance)
			throws WfCoreException {

		try {
			this.getWfActivityInstanceDao().update(wfActivityInstance);
			return this;

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}


	/**
	 * 获得活动实例变量
	 */
	public Object getVariable(String name) throws WfCoreException {

		//变量名为空就直接返回null
		if (StringUtils.isEmpty(name)) {
			return null;
		}
		
		//处理引用变量
		WfVariable variableEntity = this.getWfVariableDao().getActivityEntity(currentActivityInst.getModel().getActivityId(),
				name);
		if(variableEntity != null){
			String value = variableEntity.getValue();
			if(value.startsWith("#")){   //值的格式如：#{apply},去掉#{} 处理
				if(value.indexOf(",") != -1){
					String [] values = value.split(",");
					value = "";
					for(String val : values){
						if(StringUtils.isEmpty(val)){
							continue;
						}
						name = val.substring(2,val.length()-1);
						value += "," + getVariable(name);
					}
					if(!value.equals("")){
						return value.substring(1);
					}
				}else{
					name = value.substring(2,value.length()-1);
				}
			}
		}
		
		Object value = null;
		/**
		 * 变量查找顺序
		 * 1：变量功能作用域中 ( variableMap 变量）
		 * 2：当前活动实例中 (变量实例表)
		 * 3：当前活动实例模板中(变量实例表，统一配置)
		 * 4：原型模板中 (变量表)
		 * 5: 流程中
		 */
		// 作用域1
		if (variableMap.containsKey(name)) {
			return variableMap.get(name);
		}
		//作用域2 
		WfVariableInstance entity = this.getWfVariableInstanceDao()
				.getEntityByActivityInstId(name, currentActivityInst.getModel().getId());
		if (entity != null) {
			return entity.getValue();
		} 
		//作用域3
		entity = this.getWfVariableInstanceDao().getEntityByActivityId(name, currentActivityInst.getModel().getActivityId());
		if (entity != null) {
			return entity.getValue();
		} 
		//作用域4
		variableEntity = this.getWfVariableDao().getActivityEntity(currentActivityInst.getModel().getActivityId(),
				name);
		if(variableEntity != null){
			String varValue = variableEntity.getValue();
			while(StringUtils.isNotEmpty(varValue) && varValue.startsWith("#")){    //递归查找
				variableEntity = this.getWfVariableDao().getActivityEntity(currentActivityInst.getModel().getActivityId(),
						name);
				if(variableEntity != null){
					varValue = variableEntity.getValue();
				}
			}
			if(StringUtils.isNotEmpty(varValue) && !varValue.startsWith("#")){
				return varValue;
			}
		}
		//作用域5
		value = this.currentActivityInst.getProcessInstance().getVariable(name);
		
		if(value != null){
			return value;
			
		}else{  //都没有找到
			if(log.isDebugEnabled()){
				log.debug("没有找到" + name + "变量 ,在 activityInstId = "
						+ currentActivityInst.getModel().getId());
			}
			return null;
		}

	}


	/**
	 * 设置活动实例变量
	 * 
	 * @param name
	 * @param value
	 * @throws WfCoreException
	 */
	public void setVariable(String name, String value) throws WfCoreException {

		WfVariableInstance entity = this.getWfVariableInstanceDao().getEntityByActivityInstId(
				name, currentActivityInst.getModel().getId());
		if (entity == null) { // 新增
			entity = new WfVariableInstance();
			entity.setActivityInstId(currentActivityInst.getModel().getId());
			entity.setName(name);
			entity.setValue(value);
		} else { // 修改
			entity.setValue(value);
		}
		this.getWfVariableInstanceDao().saveOrUpdate(entity);

	}

	/**
	 * 获得业务状态
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public Object getStatus() throws WfCoreException {

		String variableName = BaseProperty.STATE_CREATE;
		Object obj = null;
		if (currentActivityInst.getProcessInstance().isEnd()) {
			variableName = BaseProperty.STATE_END;
		}
		if (subActivityInst != null) {
			obj = superActivityInst.getVariable(BaseProperty.STATE_END);
		} else {
			obj = currentActivityInst.getVariable(variableName);
		}
		return obj;
	}
	
//	/**
//	 * 设置变量实例
//	 * 
//	 * @param activityId
//	 * @throws WfCoreException
//	 */
//	private void setVariableInst() throws WfCoreException {
//
//		WfVariableSearch variableSearch = new WfVariableSearch();
//
//		variableSearch.setActivityId(currentActivityInst.getActivity()
//				.getModel().getId());
//		List<WfVariable> list = getWfVariableDao().list(variableSearch);
//		for (Iterator<WfVariable> it = list.iterator(); it.hasNext();) {
//			WfVariable wfVariable = it.next();
//
//			if (wfVariable.getValue().indexOf("#") == -1) {
//
//				Object obj = this.getVariable(wfVariable.getName());
//				if (obj == null) {
//					obj = processInstance.getVariable(wfVariable.getName());
//				}
//				if (obj == null) {
//
//					WfVariableInstance wfVariableInst = new WfVariableInstance();
//					wfVariableInst.setActivityInstId(currentActivityInst
//							.getModel().getId());
//					wfVariableInst.setName(wfVariable.getName());
//					wfVariableInst.setValue(wfVariable.getValue());
//					this.getWfVariableInstanceDao().save(wfVariableInst);
//					if (!currentActivityInst.getVariableMap().containsKey(
//							wfVariableInst.getName())) {
//						currentActivityInst.getVariableMap().put(
//								wfVariableInst.getName(),
//								wfVariableInst.getValue());
//					}
//				} else {
//					if (!currentActivityInst.getVariableMap().containsKey(
//							wfVariable.getName())) {
//						currentActivityInst.getVariableMap().put(
//								wfVariable.getName(), obj.toString());
//					}
//				}
//			}
//
//		}
//
//	}
	
	
	/**
	 * 活动结束
	 * 
	 * @param activityName
	 * @return
	 * @throws WfCoreException
	 */
	private ActivityInstance endActivity(Long nextActivityId, Long[] nextActorIds,
			Long[] nextActorGroupIds) throws WfCoreException {

		//活动完成结束后代码编写
		if (currentActivityInst.getActivity().getModel().getCategory()
				.equals(getActivityCategory(ACTIVITY_EMAIL))) { // 邮件
			
			ActivityExecHelper.sendMail(this.getWzMailSenderService(),currentActivityInst);
		}
		
		//创建下一个节点
		ActivityInstance ai = createNextActivityInst(nextActivityId, nextActorIds,
				nextActorGroupIds);
		return ai;

	}

	private ActivityInstance createNextActivityInst(Long nextActivityId, Long[] nextActorIds, Long[] nextActorGroupIds)
			throws WfCoreException {
		//
		boolean hasNextActivity = false;
		boolean canCreateNext = false;

		if (nextActivityId != null) {

			//活动用户组分配转用户分配
            ActivityExecHelper.groupToUserSave(this.getWfActivityInstUserDao(), processInstance.getModel().getId(),
            		currentActivityInst);

			//获得下一个活动
			Activity nextActivity = currentActivityInst.getActivity()
					.getProcessDefinition().loadActivityById(nextActivityId);
			WfActivity nextWfActivity = nextActivity.getModel();
			
			//当前节点任务类型
			Long taskCategory = currentActivityInst.getActivity().getModel()
					.getTaskCategory(); 
			
			//并发活动
			if (taskCategory != null
					&& getTaskCategory(TASK_CONC).equals(taskCategory)) { 

                 canCreateNext = ActivityExecHelper.concActivityExec(currentActivityInst,
                		 processInstance.getModel().getId(), this.getWfActivityInstanceDao());

             //共享活动    
			} else { 
				
				canCreateNext = ActivityExecHelper.shareActivityExec(this.getWfActivityInstUserDao(),
						currentActivityInst.getModel());
				
			}

			// 如果可以创建下一个活动
			if (canCreateNext) { 

				//结束状态
				currentActivityInst.getModel().setState(
						getActivityInstState(ACTIVITY_INST_END)); 
				//结束时间
				currentActivityInst.getModel().setEndTime(new Date());  

				//节点类型
				long category = nextWfActivity.getCategory();     
				
				// 普通或起草节点
				if (getActivityCategory(ACTIVITY_COMMON).equals(category)
						|| getActivityCategory(ACTIVITY_DRAFT).equals(category)) { 
					
					currentActivityInst = ActivityExecHelper.commonActivityExec(processInstance, nextWfActivity, 
                    		 nextActorIds, nextActorGroupIds);

				//分支节点	
				} else if (getActivityCategory(ACTIVITY_FORK).equals(category)) { 
					
					
					superActivityInst = currentActivityInst;
					subActivityInst = new HashSet<ActivityInstance>();
					List<Link> linkList = nextActivity.getLinks();
					
					//创建所有分支节点
					for (Iterator<Link> it = linkList.iterator(); it.hasNext();) {
						Link link = it.next();
						nextActivityId = getNextActivitytId(link.getModel().getActivityId(), 
								link.getModel().getName());
						ActivityInstance subActInst = createNextActivityInst(
								nextActivityId, nextActorIds,
								nextActorGroupIds);
						subActivityInst.add(subActInst);
					}
					
					
				//合并节点	
				} else if (getActivityCategory(ACTIVITY_JOIN).equals(category)) { 
					
					// 分支后的节点都走完
					WfActivityInstanceSearch aiSearch = new WfActivityInstanceSearch();
					aiSearch.setProcessInstId(processInstance.getModel()
							.getId());
					aiSearch.setState(getActivityInstState(ACTIVITY_INST_NOT_START));
					List<WfActivityInstance> aiList = this
							.getWfActivityInstanceDao().listAll(aiSearch);
					if (aiList.size() == 0) { // 所有的活动实例都完成
						List<Link> linkList = nextActivity.getLinks();
						Link link = linkList.get(0);
						nextActivityId = getNextActivitytId(link.getModel().getActivityId(), 
								link.getModel().getName());
						currentActivityInst = createNextActivityInst(nextActivityId, nextActorIds, nextActorGroupIds);
					}

					
				//决策节点	
				} else if (getActivityCategory(ACTIVITY_DECISION).equals(
						category)) { 
					
					List<Link> linkList = nextActivity.getLinks();
					for (Iterator<Link> it = linkList.iterator(); it.hasNext();) {
						Link link = it.next();
						if (link.conditionValidate(processInstance.getModel()
								.getId())) { // 链接的条件合法
							
							nextActivityId = link.getModel().getActivityId();
							currentActivityInst = createNextActivityInst(nextActivityId, nextActorIds,
									nextActorGroupIds);
							break;
						}
					}

				//邮件
				} else if (getActivityCategory(ACTIVITY_EMAIL).equals(category)) {

					currentActivityInst = processInstance
							.createActivityInstance(nextWfActivity,
									nextActorIds, nextActorGroupIds);

				// 短信
				} else if (getActivityCategory(ACTIVITY_MSG).equals(category)) { 
					
					currentActivityInst = processInstance
					.createActivityInstance(nextWfActivity,
							nextActorIds, nextActorGroupIds);
				
				// 定时器
				}  else if (getActivityCategory(ACTIVITY_TIMER).equals(category)) {

					currentActivityInst = processInstance
					.createActivityInstance(nextWfActivity,
							nextActorIds, nextActorGroupIds);
					
	

				//结束	
				}else if (getActivityCategory(ACTIVITY_END).equals(category)) { 
					hasNextActivity = true;
				}

				if (currentActivityInst != null) {
					//setVariableInst(); //
				}
				
				//没有节点就结束
				if (hasNextActivity) {  
					processInstance.end(); // 流程实例结束
				}
			}
		}
		return currentActivityInst;
	}

	
	public Long getNextActivitytId(Long preActivityId,String transName)
			throws WfCoreException {

		WfLinkSearch linkSearch = new WfLinkSearch();
		Long processDefId = this.getProcessDefinition().getModel().getId();
		linkSearch.setProcessDefId(processDefId);
		linkSearch.setPreActivityId(preActivityId);
		linkSearch.setName(transName);
		WfLink wfLink = getWfLinkDao().get(linkSearch);
		return wfLink.getActivityId();
	}
	
	/**
	 * 设置活动变量实例
	 * @param variableMap
	 * @throws WfCoreException
	 */
	private void setActivityVariables(Map<String, Object> localVariableMap) throws WfCoreException{
		
		
		if(localVariableMap == null){
			return;
		}
		
		// 获得活动变量实例
		List<WfVariable> wfVariableList = getWfVariableDao()
				.getActivityVariableList(
						currentActivityInst.getModel().getId());

		try {
			
			Set<String> set = localVariableMap.keySet();
			for (Iterator<String> iter = set.iterator(); iter.hasNext();) { // 遍历参数值
				
				String key = iter.next();
				String name = null;
				for (Iterator<WfVariable> it = wfVariableList.iterator(); it
				.hasNext();) { // 遍历流程变量
					WfVariable entity = it.next();
					name = entity.getName();
					if (name.equals(key)) {
						break;
					}
				}
				
				Object obj = localVariableMap.get(key);
				String variableValue = "";
				
				// 前台传过来的参数进行转换
				if (obj instanceof Long[]) {
					Long[] ls = (Long[]) obj;
					for (Long l : ls) {
						variableValue += ","+l.toString();
					}
					if(!variableValue.equals("")){
						variableValue = variableValue.substring(1);
					}
				} else if (obj instanceof String[]) {
					String[] ss = (String[]) obj;
					for (String s : ss) {
						variableValue += ","+s;
					}
					if(!variableValue.equals("")){
						variableValue = variableValue.substring(1);
					}
				} else {
					variableValue = obj.toString();
				}
				
				// 构建流程实例变量实例
				WfVariableInstance wfVariableInst = new WfVariableInstance();
				wfVariableInst.setActivityInstId(currentActivityInst.getModel().getId());
				wfVariableInst.setName(key);
				wfVariableInst.setValue(variableValue);
				this.getWfVariableInstanceDao().save(wfVariableInst);
				
				// 覆盖设置
				variableMap.put(wfVariableInst.getName(), wfVariableInst
						.getValue());
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new WfCoreException("活动变量实例保存失败");
		}
	}
	

	



	public Map<String, Object> getVariableMap() {
		return variableMap;
	}

	public WfActivityInstance getModel() {
		return wfActivityInstance;
	}

	public void setModel(WfActivityInstance wfActivityInstance) {
		this.wfActivityInstance = wfActivityInstance;
	}

	public Activity getActivity() {
		return activity;
	}

	public void setActivity(Activity activity) {
		this.activity = activity;
	}

	public ProcessDefinition getProcessDefinition() {
		return processDefinition;
	}

	public void setProcessDefinition(ProcessDefinition processDefinition) {
		this.processDefinition = processDefinition;
	}

	public ProcessInstance getProcessInstance() {
		return processInstance;
	}

	public void setProcessInstance(ProcessInstance processInstance) {
		this.processInstance = processInstance;
	}

}
